import { BoutState, FightState, LeisureState, PrepareState } from "../etc/BoutState";
import { LogicDriver } from "../etc/LogicDriver";
import { StateMachine, StateMachineRoot, Transition } from "../etc/StateMachine";
import { DamageInformation, UnitStage } from "../etc/UnitStage";
import { util } from "../etc/Util";
import Appearance from "../model/Appearance";
import GameModel from "../model/GameModel";
import RobotModel from "../model/RobotModel";
import CircleIndicator_Generate from "../ui-generate/CircleIndicator_generate";
import LessenCircleTimeView_Generate from "../ui-generate/LessenCircleTimeView_generate";
import WaitFightView_Generate from "../ui-generate/WaitFightView_generate";
import { BeDefeatedView } from "../ui/BeDefeatedView";
import { CircleIndicator } from "../ui/CircleIndicator";
import { NoWinnerView } from "../ui/NoWinnerView";
import { WinView } from "../ui/WinView";

export enum EnumBoutState {
    // 空闲
    leisure,
    // 准备(报名)
    prepare,
    // 战斗
    fight,
}

export class BoutModuleC extends ModuleC<BoutModuleS, null> {
    // 玩家是否参加对局状态变更
    onPlayerSignStateChanged: Action = new Action()
    // 玩家成功击球事件
    onPlayerHitBallSuccess: Action = new Action()
    // 是否加入对局
    signedFighting = true
    // 因为暂停游戏注册对局时设置为true,恢复游戏时重新加入对局并设置为false
    private resumeMark = false

    private circleObject:GameObject

    circleCenter:Vector = Vector.zero
    circleRadius:number = 100

    private waitFightView:WaitFightView_Generate
    private lessenCircleTimeView:LessenCircleTimeView_Generate

    protected onStart() {
        // 默认加入对局
        this.send_signup_fighting()
        // 当客户端被挂起则退出注册的对局
        SystemUtil.onPause.add(() => {
            if (this.signedFighting == false) return
            this.resumeMark = true
            this.send_exit_fighting()
        })
        // 重新加入对局
        SystemUtil.onResume.add(() => {
            if (this.resumeMark == false) return
            this.resumeMark = false
            this.send_signup_fighting()
        })

        this.circleObject = GameObject.findGameObjectById('2C4AC3C7')
        this.waitFightView = UIService.getUI(WaitFightView_Generate)
        this.lessenCircleTimeView = UIService.getUI(LessenCircleTimeView_Generate)

        GameModel.instance.onBoutStateChangedEvent.add(this.onBoutStateChanged, this)
        GameModel.instance.onBoutFightCharacterArrayChanged.add(this.onBoutStateChanged, this)
        GameModel.instance.onFightingBeginTimeChanged.add(this.onFightingBeginTimeChanged, this)
        GameModel.instance.onLessenCircleTimeChanged.add(this.onLessenCircleTimeChanged, this)
        GameModel.instance.onBoutStateChangedEvent.add(this.onLessenCircleTimeChanged, this)
    }

    protected onUpdate(dt: number): void { }

    private onBoutStateChanged(){
        let currentState = GameModel.instance.boutState
        let playerInFighting = GameModel.instance.fightingCharacter.includes(this.localPlayer.playerId)
        // 对局状态&在对局内
        if(currentState == EnumBoutState.fight && playerInFighting){
            UIService.show(CircleIndicator)
        }else{
            UIService.hide(CircleIndicator)
        }
        // 对局状态显示人数
        if(currentState == EnumBoutState.prepare){
            // console.log(`当前战斗人数:${GameModel.instance.fightingCharacter.length}`);
        }else{
            
        }
    }

    // 比赛开始倒计时变更
    private onFightingBeginTimeChanged(){
        if(GameModel.instance.fightingBeginTime > 0.4) {
            UIService.showUI(this.waitFightView)
            let second = Math.floor(GameModel.instance.fightingBeginTime)
            this.waitFightView.txt_context.text = `对局${second}秒后开始, 请准备...`
        }else{
            UIService.hideUI(this.waitFightView)
        }
    }

    // 缩圈倒计时变更
    private onLessenCircleTimeChanged(){
        //距离安全区更新还剩XX秒
        if(GameModel.instance.nextLessenCircleTime > 0.2 && GameModel.instance.boutState == EnumBoutState.fight) {
            UIService.showUI(this.lessenCircleTimeView)
            let second = Math.floor(GameModel.instance.nextLessenCircleTime)
            this.lessenCircleTimeView.txt_context.text = `距离安全区更新还剩${second}秒!`
        }else{
            UIService.hideUI(this.lessenCircleTimeView)
        }
    }

    // 注册
    send_signup_fighting() {
        this.signedFighting = true
        this.server.net_sign_up_fight()
        this.onPlayerSignStateChanged.call()
    }

    // 离开
    send_exit_fighting() {
        this.signedFighting = false
        this.server.net_exit_fight()
        this.onPlayerSignStateChanged.call()
    }

    // 强制传送
    net_safe_translate_position(position: number[]) {
        Player.localPlayer.character.worldTransform.position = util.getTemporaryVector(position[0], position[1], position[2])
    }
    
    // 圈的位置更新
    net_sync_circle_range(pos: number[], radius: number) {
        this.circleCenter = new Vector(pos[0], pos[1], pos[2])
        this.circleRadius = radius

        this.circleObject.worldTransform.position = this.circleCenter
        this.circleObject.worldTransform.scale = new Vector(radius, radius, radius)
    }

    // 玩家失败
    net_character_be_defeated(sceneID: number) {
        let name:string
        if(RobotModel.isRobot(sceneID)){
            name = RobotModel.robotMap.get(sceneID)?.cfg?.Name
        }else{
            name = Appearance.AppearanceMap.get(sceneID)?.playerName
        }
        if(!name) return
        let ui = UIService.show(BeDefeatedView)
        ui.setInfo(name)
    }
    
    net_sync_winner(sceneID: number) {
        let name:string
        if(RobotModel.isRobot(sceneID)){
            name = RobotModel.robotMap.get(sceneID)?.cfg?.Name
        }else{
            name = Appearance.AppearanceMap.get(sceneID)?.playerName
        }
        if(!name) return
        let ui = UIService.show(WinView)
        ui.setInfo(name)
    }

    net_sync_no_winner() {
        UIService.show(NoWinnerView)
    }
}

export class BoutModuleS extends ModuleS<BoutModuleC, null> {
    // 玩家击杀事件
    onPlayerKillOtherCharacterEvent: Action1<number> = new Action1()
    // 玩家胜利事件
    onPlayerWinFightEvent: Action1<number> = new Action1()
    // 玩家胜利事件(带名次排行)
    onPlayerWinFightWithRankEvent: Action2<number, number> = new Action2()
    // 当玩家击球
    onPlayerHitBall: Action1<number> = new Action1()
    // 玩家触发击球的时候的参数(key:playerID, value:dir)
    playerGatherArguments: Map<number, Vector> = new Map()
    // 注册参与战斗玩家的ID集合
    signupPlayerArray: number[] = []
    // 回合状态机
    fsm: StateMachineRoot

    protected onStart() {
        this.fsm = new StateMachine<undefined, EnumBoutState>(true).addState(EnumBoutState.leisure, new LeisureState())
            .addState(EnumBoutState.prepare, new PrepareState()).addState(EnumBoutState.fight, new FightState())
            .addTransition(new Transition(EnumBoutState.leisure, EnumBoutState.prepare))
            .addTransition(new Transition(EnumBoutState.prepare, EnumBoutState.fight))
            .addTransition(new Transition(EnumBoutState.fight, EnumBoutState.leisure))
        this.fsm.onInit()

        LogicDriver.bindLogicLoop(this.fsm.onLogicUpdate.bind(this.fsm))
    }

    protected onUpdate(dt:number): void {
        this.fsm.onUpdate(dt)
    }

    protected onPlayerEnterGame(player: mw.Player): void {
        // 注册到可攻击池子内
        UnitStage.addUnitToStage({
            sceneID: player.playerId,
            attackableGameObject: player.character,
            hitCallback: this.onPlayerBeHit,
            caller: this
        })
    }

    protected onPlayerLeft(player: Player): void {
        let playerID = player.playerId
        this.signupPlayerArray = this.signupPlayerArray.filter(id => { return id != playerID });
        (this.fsm.activeState as BoutState).onPlayerExitGame(playerID)
        this.playerGatherArguments.delete(playerID)
        // 移除可被攻击的物体
        UnitStage.removeUnitFromStage(playerID)
        // 剔除战斗列表的玩家
        if(this.fsm.id == EnumBoutState.fight){
            (this.fsm.activeState as FightState).onPlayerExitGame(player.playerId)
        }
        
    }

    private onPlayerBeHit(damageMessage: DamageInformation) {
        let targetCharacter = GameModel.instance.getCharacterBySceneID(damageMessage.targetSceneID)
        let formCharacter = GameModel.instance.getCharacterBySceneID(damageMessage.fromSceneID)
        
        if (!targetCharacter || !formCharacter) {
            if(!targetCharacter) console.error(`缺少目标方受击信息!`);
            if(!formCharacter) console.error(`缺少发起方受击信息!`);
            return
        }
        let dir = Vector.subtract(targetCharacter.worldTransform.position, formCharacter.worldTransform.position).normalized
        dir.z = 0.8
        targetCharacter.addImpulse(targetCharacter.velocity.multiply(-1))
        targetCharacter.addImpulse(dir.multiply(1200), true)
        EffectService.playAtPosition('151580', targetCharacter.worldTransform.position, { scale: new Vector(2, 2, 2) })
    }

    // 玩家报名参加
    net_sign_up_fight() {
        if (this.signupPlayerArray.includes(this.currentPlayerId)) return
        this.signupPlayerArray.push(this.currentPlayerId)
    }

    // 玩家退出报名
    net_exit_fight() {
        this.signupPlayerArray = this.signupPlayerArray.filter(id => { return id != this.currentPlayerId })
    }

    // 同步玩家死亡
    syncCharacterBeDefeated(sceneID:number){
        this.getAllClient().net_character_be_defeated(sceneID)
    }

    // 使用可靠连接传送玩家
    safeTranslatePlayer(playerID: number, position: Vector) {
        if (!Player.getPlayer(playerID)) return;
        this.getClient(playerID).net_safe_translate_position([position.x, position.y, position.z])
    }

    // 同步给所有客户端圈的信息
    syncCircleRange(center:Vector, radius:number){
        let pos = [Math.round(center.x), Math.round(center.y), Math.round(center.z)]
        this.getAllClient().net_sync_circle_range(pos, radius)
    }

    // 通知前端此次对局无人胜利
    syncNoWinner() {
        this.getAllClient().net_sync_no_winner()
    }

    // 通知前端胜利者
    syncWinner(sceneID: number) {
        this.getAllClient().net_sync_winner(sceneID)
    }
}